
#include "AtomNumFilterMsgr.hh"

#include <memory>

#include "AtomNumFilter.hh"
#include "G4Tokenizer.hh"
#include "G4UIcommand.hh"
#include "G4UIdirectory.hh"
#include "Util.hh"

// #include "G4ScoringManager.hh"
// #include "G4SystemOfUnits.hh"

// #include "G4VPrimitiveScorer.hh"  //for debug
// #include "G4VScoringMesh.hh"
// #include "G4UIcmdWithAString.hh"
// #include "G4UIcmdWithAnInteger.hh"

using std::make_unique;

//AtomNumFilter* AtomNumFilterMsgr::fFilter = nullptr;

//AtomNumFilterMsgr::AtomNumFilterMsgr(G4ScoringManager* SManager)
//AtomNumFilterMsgr::AtomNumFilterMsgr(AtomNumFilter* filter)
AtomNumFilterMsgr::AtomNumFilterMsgr(std::vector<AtomNumFilter*> filter_vec)
    //  : fSMan(SManager)
    //: fFilter(filter)
    : _fFilter_vec(filter_vec)
{
    G4cout << "Registering AtomNumFilter commands..." << G4endl;
    //G4cout << "Scoring manager address: " << fSMan << G4endl;

    G4UIparameter* param{};

    _fFilterDir = make_unique<G4UIdirectory>("/score/filter/AtomNumFilter/", true);
    _fFilterDir->SetGuidance("Commands to configure AtomNumFilter");

    _fCmdCreateFilter = make_unique<G4UIcommand>("/score/filter/AtomNumFilter/create", this, true);
    _fCmdCreateFilter->SetGuidance("Create and bind an AtomNumFilter to the current scorer.");
    _fCmdCreateFilter->SetGuidance("[usage] /score/filter/AtomNumFilter/create fname targetZ Zmax category");

    param = new G4UIparameter("fname", 's', false);
    _fCmdCreateFilter->SetParameter(param);

    param = new G4UIparameter("targetZ", 'i', false);
    param->SetDefaultValue("6");
    _fCmdCreateFilter->SetParameter(param);

    param = new G4UIparameter("Zmax", 'i', false);
    param->SetDefaultValue("100");
    _fCmdCreateFilter->SetParameter(param);

    param = new G4UIparameter("cat", 's', false);
    param->SetDefaultValue("primary");
    _fCmdCreateFilter->SetParameter(param);

    _fCmdCreateFilter->AvailableForStates(G4State_PreInit, G4State_Idle);

    /*
  fCmdSetTargetZ = new G4UIcmdWithAnInteger("/score/filter/AtomNumFilter/setTargetZ", this);
  fCmdSetTargetZ->SetGuidance("Set target atomic number for the filter");
  fCmdSetTargetZ->SetParameterName("targetZ", false);
  fCmdSetTargetZ->AvailableForStates(G4State_PreInit, G4State_Idle);

  fCmdSetZmax = new G4UIcmdWithAnInteger("/score/filter/AtomNumFilter/setZmax", this);
  fCmdSetZmax->SetGuidance("Set max atomic number for the filter");
  fCmdSetZmax->SetParameterName("Zmax", false);
  fCmdSetZmax->AvailableForStates(G4State_PreInit, G4State_Idle);

  // 参数可为 "primary", "nonprimary", "any"
  fCmdSetCat = new G4UIcmdWithAString("/score/filter/AtomNumFilter/setCat", this);
  fCmdSetCat->SetGuidance("Set filter cat: primary, nonprimary, or any");
  fCmdSetCat->SetParameterName("cat", false);
  fCmdSetCat->AvailableForStates(G4State_PreInit, G4State_Idle);
   */
}

AtomNumFilterMsgr::~AtomNumFilterMsgr()
{
    //delete _fCmdCreateFilter;
    //delete fCmdSetTargetZ;
    //delete fCmdSetZmax;
    //delete fCmdSetCat;
    // delete _fFilterDir;
    // if(fFilter) {
    //   delete fFilter;
    //   fFilter = nullptr;
    // }
    Util::Clear(_fFilter_vec);
}

void AtomNumFilterMsgr::SetNewValue(G4UIcommand* command, G4String newValue)
{
    //G4VScoringMesh* mesh = fSMan->GetCurrentMesh();
    //G4ScoringManager* sm = G4ScoringManager::GetScoringManager();
    //G4VScoringMesh* mesh = sm->GetCurrentMesh();

    //G4TokenVec token;
    //FillTokenVec(newValue,token);

    if (command == _fCmdCreateFilter.get())
    {
        G4TokenVec token;
        FillTokenVec(newValue, token);
        G4cout << "AtomNumFilterMsgr::SetNewValue executing..." << G4endl;

        //G4ScoringManager* sm = G4ScoringManager::GetScoringManager();
        //G4VScoringMesh* mesh = sm->GetCurrentMesh();
        //AtomNumFilter* filter = new AtomNumFilter(newValue);;
        //if (mesh) {
        //  if(!mesh->IsCurrentPrimitiveScorerNull()) {
        G4String& name = token[0];
        G4int targetZ = StoI(token[1]);
        G4int Zmax = StoI(token[2]);
        G4String& cat = token[3];
        /*
        if (!fFilter) {
          fFilter = new AtomNumFilter(name, targetZ, Zmax, cat);
          //fFilter->SetAtomNumFilterArgs(targetZ, Zmax, cat);
          G4cout << "AtomNumFilterMsgr::SetNewValue: fFilter address " << fFilter << G4endl;
          G4cout << "AtomNumFilterMsgr::SetNewValue fFilter name:" << fFilter->GetName() << G4endl;
        } else {
          G4cout << "ERROR: scorer filter already exists. Command ignored." << G4endl;
        }
        */

        // 宏文件中定义了多个filter时:
        _fFilter_vec.push_back(new AtomNumFilter(name, targetZ, Zmax, cat));

        //fFilter->SetAtomNumFilterArgs(name, targetZ, Zmax, cat);
        //    mesh->SetFilter(fFilter);
        //    AtomNumFilter* myfilter = new AtomNumFilter(name, fCurrentTargetZ, fCurrentZmax, fCurrentCat);
        //mesh->SetFilter(new AtomNumFilter(name, targetZ, Zmax, cat));  // Bind the filter
        //     mesh->SetFilter(myfilter);
        //     G4cout << "AtomNumFilter bound to mesh '" << mesh->GetWorldName() << "'" << G4endl;
        //     G4cout << "AtomNumFilter: " << name << "  " << targetZ << "  " << Zmax << "  " << cat << G4endl;

        //     G4VPrimitiveScorer* scorer = mesh->GetPrimitiveScorer("eDep");
        //     if(mesh->GetPrimitiveScorer("eDep")) {
        //       G4cout << "PrimitiveScorer is eDep" << G4endl;
        //       G4cout << "eDep's filter: " << scorer->GetFilter()->GetName() << G4endl;
        //       scorer->SetVerboseLevel(1);
        //       G4cout << "eDep's verbose level: " << scorer->GetVerboseLevel() << G4endl;
        //     }
        //   } else {
        //     G4cout << "Warning: scorer is not set." << G4endl;
        //   } else {
        //     G4cout << "Error: Mesh not found." << G4endl;
        //   }
        // }
        //     fFilter->SetAtomNumFilterArgs(name, targetZ, Zmax, cat);
    }
    /*
  else if (command == fCmdSetTargetZ) {
    G4int targetZ = fCmdSetTargetZ->GetNewIntValue(newValue);
    G4ScoringMesh* mesh = fSMan->GetCurrentMesh();
    if (mesh) {
      G4VPrimitiveScorer* scorer = mesh->GetPrimitiveScorer
    }
    fFilter->SetTargetZ(targetZ);
  }
  else if (command == fCmdSetZmax) {
    G4int Zmax = fCmdSetZmax->GetNewIntValue(newValue);
    fFilter->SetZmax(Zmax);
  }
  else if (command == fCmdSetCat) {
    fFilter->SetCat(newValue);
  }
  */
}

void AtomNumFilterMsgr::FillTokenVec(G4String newValues, G4TokenVec& token)
{
    G4Tokenizer next(newValues);
    G4String val;
    while (!(val = next()).empty())
    {
        token.push_back(val);
    }
}

//AtomNumFilter* AtomNumFilterMsgr::GetFilter() {
//  return fFilter;
//}